package cn.edu.scut.suggestion;

/**
 * 使用概率模型实现输入查询词推荐
 * @author tian.yuchen
 */

import java.io.File;
import java.util.HashSet;
import java.util.Vector;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.lucene.util.PriorityQueue;

import cn.edu.scut.suggestion.corpus.MysqlHelper;
import cn.edu.scut.suggestion.corpus.TermInfo;
import cn.edu.scut.suggestion.segmentation.Segment;
import cn.edu.scut.suggestion.tools.Configuration;

public class ExpandSuggest {
	Configuration conf;
	File file;
	public ExpandSuggest(){
		conf = new Configuration();
		file = new File(conf.get("corpus.db").toString());
	}
	
	public JSONObject getNExpandSugg(String srcquery,int N){
		String preString="";
		JSONArray jArray=new JSONArray();
		JSONObject jObject=new JSONObject();
	//	System.out.println("expand: "+srcquery);
		Vector<String> itemsstr=Segment.split(srcquery);
		if (itemsstr.size()==0){
			jObject.put("data", "");
			return jObject;
		}
		MysqlHelper mHelper=new MysqlHelper();
		Vector<TermInfo> candidates=mHelper.getCandidatesWithDBByText(itemsstr.lastElement(),file);
	//	System.out.println("itemsstr.lastElement(): "+itemsstr.lastElement());
		TermInfo qc;
		if(itemsstr.size()==1){
			qc=mHelper.getTermWithDocsByText(itemsstr.get(0), file);
		}else {
			qc=mHelper.getTermWithDocsByText(itemsstr.get(itemsstr.size()-2), file);
			for (int i = 0; i < itemsstr.size()-1; i++) {
				preString+=itemsstr.get(i);
			}
		}
		
		//for the experiment with SimSearch comment by tyc 2013.12.25
		Vector<TermInfo> resv=getMaxNTerms(N, candidates, qc);    //ProbSearch
		//Vector<TermInfo> resv=getMaxNTermsSimSearch(N, candidates, qc);    //SimSearch
		
		for (TermInfo termInfo : resv) {
			jArray.add(preString+termInfo.term.text());
		}
		jObject.put("data", jArray);
		System.out.println(jObject.toString());
		return jObject;
	}
	
	public Vector<TermInfo> getMaxNTerms(int N,Vector<TermInfo> candidates,TermInfo qc){
		
		TermInfoQueue tiq = new TermInfoQueue(N);
			double minp = 0;
			for (TermInfo can : candidates) {
				double p=CiQt(can)*QcCi(qc, can);
				if (p > minp) {
					tiq.insertWithOverflow(new PTermInfo(can, p));
					if (tiq.size() >= N) // if tiq overfull
					{
						tiq.pop(); // remove lowest in tiq
						minp = ((PTermInfo) tiq.top()).p; // reset minFreq
					}
				}
			}
			Vector<TermInfo> resInfos=new Vector<TermInfo>();
			while(tiq.size()>0){
				resInfos.add(tiq.pop().termInfo);
			}
		return resInfos;
	}
	
	//This function is used to finish the experiment with SimSearch  2013.12.25
	public Vector<TermInfo> getMaxNTermsSimSearch(int N,Vector<TermInfo> candidates,TermInfo qc){
		TermInfoQueue tiq = new TermInfoQueue(N);
		double minp = 0;
		for (TermInfo can : candidates) {
			double p=can.docFreq;
			if (p > minp) {
				tiq.insertWithOverflow(new PTermInfo(can, p));
				if (tiq.size() >= N) // if tiq overfull
				{
					tiq.pop(); // remove lowest in tiq
					minp = ((PTermInfo) tiq.top()).p; // reset minFreq
				}
			}
		}
		Vector<TermInfo> resInfos=new Vector<TermInfo>();
		while(tiq.size()>0){
			resInfos.add(tiq.pop().termInfo);
		}
	return resInfos;
}
	
	public double CiQt(TermInfo ci){
		double res=ci.docFreq*ci.idf;
		return res;
	}
	
	public double QcCi(TermInfo qc,TermInfo ci){
		if (qc.equals(ci))
			return 1.0;
		HashSet<Integer> interset = new HashSet<Integer>();
		TermInfo xx = qc;
		TermInfo yy = ci;
		int inter = 0;
		for (Integer xt : xx.docs) {
			interset.add(xt);
		}
		for (Integer yt : yy.docs) {
			if (interset.contains(yt)) {
				inter++;
			}
		}
		double res = (double) inter
				/ Math.sqrt(xx.docs.size() * yy.docs.size());
		return res;
	}
	
	final class TermInfoQueue extends PriorityQueue<PTermInfo> {
		TermInfoQueue(int size) {
			initialize(size);
		}

		@Override
		protected boolean lessThan(PTermInfo arg0, PTermInfo arg1) {
			return arg0.p<arg1.p;
		}
	}
	
	final class PTermInfo {
		TermInfo termInfo;
		double p;

		PTermInfo(TermInfo termInfo, double p) {
			this.termInfo = termInfo;
			this.p = p;
		}
	}

	public static void main(String[] args) {
		ExpandSuggest eg=new ExpandSuggest();
		JSONObject resj= eg.getNExpandSugg("一",10);
		System.out.println(resj.toString());
	}
}
